﻿using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Cubicle.Core.Config;
using Cubicle.Core.Interfaces;

namespace Cubicle.Core.Shared
{
    public static class ContainerServices
    {

        private static NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();

        static ContainerServices()
        {
            // Add in-memory assemblies
            _logger.Info("Registering AppDomain events...".Format());
            AppDomain.CurrentDomain.TypeResolve += TypeCache.AutoTypeResolve;
            AppDomain.CurrentDomain.AssemblyLoad += TypeCache.AutoTypeCache;
            AppDomain.CurrentDomain.AssemblyResolve += TypeCache.AutoAssemblyResolve;

            // Init type cache caching all in-memory assemblies
            _logger.Info("Performing type caching...".Format());
            TypeCache.CacheAll();
        }

        public static CompositionContainer CreateContainer()
        {
            //var rConfig = BaseConfig.Read<EngineConfig>();

            //// Register parts from all assemblies
            //var aggCatalog = new AggregateCatalog();
            //foreach (var codeBase in rConfig.Assemblies.Where(x => !string.IsNullOrEmpty(x)))
            //    aggCatalog.Catalogs.Add(new AssemblyCatalog(codeBase));

            //// Add reflected types to container
            //var types = TypeCache.ListCachedTypes();
            //aggCatalog.Catalogs.Add(new TypeCatalog(types));

            //// Add base directory
            //foreach (var dir in new[] { ".", ".\bin" })
            //{
            //    if (!Directory.Exists(dir)) continue;
            //    aggCatalog.Catalogs.Add(new DirectoryCatalog(dir, "*.dll"));
            //    aggCatalog.Catalogs.Add(new DirectoryCatalog(dir, "*.exe"));
            //}

            //// Create a container an import the message object
            //var container = new CompositionContainer(aggCatalog);

            var container = new CompositionContainer(SelfUpdatingCatalog.AggCatalog);
            container.ComposeExportedValue(container);
            return container;
        }

        public static IProcessor<T> Create<T>(CompositionContainer container, ProcessorConfig config)
        {
            _logger.Trace(Helpers.Format("Creating processor: {0}", config.Key));

            // If there are no sub-processors, don't create a queue
            if (config.Queue == null || config.Queue.Count == 0)
                return container.GetExportedValue<IProcessor<T>>(config.Key);

            // If there are sub processors, Create a queue
            var processor = container.GetExportedValue<IProcessor<T>>(config.Key);
            var procQueue = (IProcessorQueue)processor;

            // Create all sub-processes
            foreach (var conf in config.Queue)
                procQueue.AddProcessor(container, conf);

            return processor;
        }

    }
}
